package com.ai.bitcoin.aop.logging;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 日期切面
 */
@Aspect
@Component
public class LoggingAspect {

    private final static Marker AOP_MARKER = MarkerFactory.getMarker("AOP");
    //允许最大耗时（毫秒）
    private final int MAX_APPLY_TIME = 3000;
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 外部访问Controller切入
     */
    @Pointcut("within(com.ai.bitcoin.controller..*)")
    public void controllerPointcut() {
    }

    /**
     * 后台切入
     */
    @Pointcut("within(com.ai.bitcoin.service..*)" +
            "|| within(com.ai.bitcoin.queue..*) " +
            "|| within(com.ai.bitcoin.redis..*)" +
            "|| within(com.ai.bitcoin.schedule..*)" +
            "")
    public void applicationPointcut() {
        // Method is empty as this is just a Pointcut, the implementations are in the advices.
    }

    /**
     * 异常切入
     */
    @AfterThrowing(pointcut = "applicationPointcut()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        log.error(AOP_MARKER, "系统发生 {}.{}() 原因 = \'{}\' and 异常内容 = \'{}\'", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName(), e.getCause() != null ? e.getCause() : "NULL", e.getMessage(), e);

    }


    @Around("controllerPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            long costTime = System.currentTimeMillis() - startTime;
            if (costTime >= MAX_APPLY_TIME) {
                log.warn(AOP_MARKER, "耗时过长请求[{}ms]：: {}.{}() 请求参数 = {}", costTime, joinPoint.getSignature().getDeclaringTypeName(),
                        joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
            }
            return result;
        } catch (IllegalArgumentException e) {
            log.error(AOP_MARKER, "请求异常: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()),
                    joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());

            throw e;
        }
    }
}
